package com.easychat.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import com.easychat.constants.Constants;
import com.easychat.entity.config.AppConfig;
import com.easychat.entity.dto.MessageSendDTO;
import com.easychat.entity.dto.TokenUserInfoDTO;
import com.easychat.entity.enums.*;
import com.easychat.entity.po.ChatSessionUser;
import com.easychat.entity.po.UserContact;
import com.easychat.entity.po.UserInfoBeauty;
import com.easychat.entity.query.ChatSessionUserQuery;
import com.easychat.entity.query.UserContactQuery;
import com.easychat.exception.BusinessException;
import com.easychat.mappers.ChatSessionUserMapper;
import com.easychat.mappers.UserContactMapper;
import com.easychat.mappers.UserInfoBeautyMapper;
import com.easychat.redis.RedisComponent;
import com.easychat.service.UserContactService;
import com.easychat.websocket.MessageHandler;
import org.apache.catalina.User;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.easychat.entity.query.UserInfoQuery;
import com.easychat.entity.po.UserInfo;
import com.easychat.entity.vo.PaginationResultVO;
import com.easychat.entity.query.SimplePage;
import com.easychat.mappers.UserInfoMapper;
import com.easychat.service.UserInfoService;
import com.easychat.utils.StringTools;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;


/**
 * 用户信息 业务接口实现
 */
@Service("userInfoService")
public class UserInfoServiceImpl implements UserInfoService {

	@Resource
	private UserInfoMapper<UserInfo, UserInfoQuery> userInfoMapper;
	@Resource
	private UserInfoBeautyMapper<UserInfoBeauty, UserInfoQuery> userInfoBeautyMapper;
	@Resource
	private UserContactMapper<UserContact, UserContactQuery> userContactMapper;
	@Resource
	private ChatSessionUserMapper<ChatSessionUser, ChatSessionUserQuery> chatSessionUserMapper;
	@Resource
	private UserContactService userContactService;
	@Resource
	private AppConfig appConfig;
	@Resource
	private RedisComponent redisComponent;
	@Resource
	private MessageHandler messageHandler;

	/**
	 * 根据条件查询列表
	 */
	@Override
	public List<UserInfo> findListByParam(UserInfoQuery param) {
		return this.userInfoMapper.selectList(param);
	}

	/**
	 * 根据条件查询列表
	 */
	@Override
	public Integer findCountByParam(UserInfoQuery param) {
		return this.userInfoMapper.selectCount(param);
	}

	/**
	 * 分页查询方法
	 */
	@Override
	public PaginationResultVO<UserInfo> findListByPage(UserInfoQuery param) {
		int count = this.findCountByParam(param);
		int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

		SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
		param.setSimplePage(page);
		List<UserInfo> list = this.findListByParam(param);
		PaginationResultVO<UserInfo> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
		return result;
	}

	/**
	 * 新增
	 */
	@Override
	public Integer add(UserInfo bean) {
		return this.userInfoMapper.insert(bean);
	}

	/**
	 * 批量新增
	 */
	@Override
	public Integer addBatch(List<UserInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.userInfoMapper.insertBatch(listBean);
	}

	/**
	 * 批量新增或者修改
	 */
	@Override
	public Integer addOrUpdateBatch(List<UserInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.userInfoMapper.insertOrUpdateBatch(listBean);
	}

	/**
	 * 多条件更新
	 */
	@Override
	public Integer updateByParam(UserInfo bean, UserInfoQuery param) {
		StringTools.checkParam(param);
		return this.userInfoMapper.updateByParam(bean, param);
	}

	/**
	 * 多条件删除
	 */
	@Override
	public Integer deleteByParam(UserInfoQuery param) {
		StringTools.checkParam(param);
		return this.userInfoMapper.deleteByParam(param);
	}

	/**
	 * 根据UserId获取对象
	 */
	@Override
	public UserInfo getUserInfoByUserId(String userId) {
		return this.userInfoMapper.selectByUserId(userId);
	}

	/**
	 * 根据UserId修改
	 */
	@Override
	public Integer updateUserInfoByUserId(UserInfo bean, String userId) {
		return this.userInfoMapper.updateByUserId(bean, userId);
	}

	/**
	 * 根据UserId删除
	 */
	@Override
	public Integer deleteUserInfoByUserId(String userId) {
		return this.userInfoMapper.deleteByUserId(userId);
	}

	/**
	 * 根据Email获取对象
	 */
	@Override
	public UserInfo getUserInfoByEmail(String email) {
		return this.userInfoMapper.selectByEmail(email);
	}

	/**
	 * 根据Email修改
	 */
	@Override
	public Integer updateUserInfoByEmail(UserInfo bean, String email) {
		return this.userInfoMapper.updateByEmail(bean, email);
	}

	/**
	 * 根据Email删除
	 */
	@Override
	public Integer deleteUserInfoByEmail(String email) {
		return this.userInfoMapper.deleteByEmail(email);
	}

	/**
	 * 注册
	 * @param email 邮箱
	 * @param password 密码
	 * @param nickName 昵称
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = {Exception.class})
	public void register(String email, String password, String nickName) {
		//判断email是否重复
		UserInfo userInfo = userInfoMapper.selectByEmail(email);
		if (userInfo != null) {
			throw new BusinessException("注册邮箱已经存在");
		}
		//userId共12位，"U" + 11位随机序列 ”U“开头代表用户ID
		String userId = StringTools.getUserId();
		//查询靓号表中是否有此email，status是否为使用过
		//何时设置靓号：靓号表中有此email且对应状态为未使用
		UserInfoBeauty userInfoBeauty = userInfoBeautyMapper.selectByEmail(email);
		if (userInfoBeauty != null && userInfoBeauty.getStatus().equals(BeautyAccountStatusEnum.UNUSED.getStatus())) {
			//设置靓号，即将userID设置为靓号表中存储的userId
			userId = userInfoBeauty.getUserId();
			//这个靓号已经使用过了，要设置状态为已使用
			userInfoBeauty.setStatus(BeautyAccountStatusEnum.USED.getStatus());
			userInfoBeautyMapper.updateByIdAndUserId(userInfoBeauty, userInfoBeauty.getId(), userInfoBeauty.getUserId());
		}
		//向user_info表中插入注册数据
		Date curDate = new Date();
		UserInfo userInfo1 = new UserInfo();
		userInfo1.setUserId(userId);
		userInfo1.setEmail(email);
		userInfo1.setNickName(nickName);
		userInfo1.setJoinType(JoinTypeEnum.PENDING_REVIEW.getType());//默认：待审核
		//注意：存密码时要用MD5加密
		userInfo1.setPassword(StringTools.encodeMD5(password));
		userInfo1.setCreateTime(curDate);
		userInfo1.setStatus(UserStatusEnum.ENABLE.getStatus());
		userInfo1.setLastOffTime(curDate.getTime());
		userInfoMapper.insert(userInfo1);
		//TODO completed1 创建机器人好友
		userContactService.addContact4Robot(userId);
	}

	/**
	 * 登录
	 * @param email 邮箱
	 * @param password 密码
	 * @return
	 */
	@Override
	public TokenUserInfoDTO login(String email, String password) {
		//根据邮箱查询
		UserInfo userInfo = userInfoMapper.selectByEmail(email);
		if (userInfo == null) {
			throw new BusinessException("账号不存在");
		}
//		if (!userInfo.getPassword().equals(StringTools.encodeMD5(password))) {
//			throw new BusinessException("密码错误");
//		}
		if (!userInfo.getPassword().equals(password)) {//传过来的password是md5加密后的
			throw new BusinessException("密码错误");
		}
		if (userInfo.getStatus().equals(UserStatusEnum.DISABLE.getStatus())) {
			throw new BusinessException("账号已禁用");
		}
        //查询联系人列表(联系人id列表)
		UserContactQuery userContactQuery = new UserContactQuery();
		userContactQuery.setUserId(userInfo.getUserId());
		userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
		List<UserContact> contactList = userContactMapper.selectList(userContactQuery);
		List<String> contactIdList = new ArrayList<>();
		for (UserContact userContact : contactList) {
			contactIdList.add(userContact.getContactId());
		}
		//先清空，再将联系人列表保存到redis
		redisComponent.cleanUserContact(userInfo.getUserId());
		if (!contactIdList.isEmpty()) {
			redisComponent.saveUserContactBatch(userInfo.getUserId(), contactIdList);
		}

		TokenUserInfoDTO tokenUserInfoDTO = this.getTokenUserInfoDTO(userInfo);
		//如果心跳存在，说明该用户已经登录了，登陆失败
		Long lastHeartBeat = redisComponent.getUserHeartBeat(userInfo.getUserId());
		if (lastHeartBeat != null) {
			throw new BusinessException("此账号已经在别处登录，请退出后再登录");
		}
		//生成token 前面加上userId进一步降低了重复的可能
		String token = StringTools.encodeMD5(userInfo.getUserId() + StringTools.getRandomString(Constants.LENGTH_20));
		tokenUserInfoDTO.setToken(token);
		//将tokenUserInfoDTO(登录信息)存入redis
		redisComponent.saveTokenUserInfoDTO(tokenUserInfoDTO);
		return tokenUserInfoDTO;
	}

	/**
	 * 修改用户信息
	 * @param userInfo 用户信息对象
	 * @param avatarFile 头像
	 * @param avatarCover 头像缩略图
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateUserInfo(UserInfo userInfo, MultipartFile avatarFile, MultipartFile avatarCover) throws IOException {
		if (avatarFile != null) {
			//修改头像
			//文件根目录
			String baseFolder = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE;//文件存储路径
			//头像存储目录
			File avatarFileFolder = new File(baseFolder + Constants.FILE_FOLDER_AVATAR);
			if (!avatarFileFolder.exists()){
				avatarFileFolder.mkdirs();
			}
			//图片文件命名规则：userId.png
			//保存原图和缩略图
			//注意：后面传的会覆盖先传的
			String filePath = avatarFileFolder.getPath() + "/" + userInfo.getUserId() + Constants.IMAGE_EXTENSION;
			//String coverPath = avatarFileFolder.getPath() + "/" + userInfo.getUserId() + Constants.COVER_IMAGE_EXTENSION;
			String coverPath = filePath + Constants.COVER_IMAGE_EXTENSION;
			avatarFile.transferTo(new File(filePath));
			avatarCover.transferTo(new File(coverPath));
		}
		UserInfo dbUserInfo = userInfoMapper.selectByUserId(userInfo.getUserId());
		userInfoMapper.updateByUserId(userInfo, userInfo.getUserId());//更新数据库

		//更新相关表冗余信息 chat_session_user表中的contact_name字段
		//如果userId对应的用户改了昵称，那么：
		//1.redis中存的userId对应的token信息要修改，因为其中包含昵称
		//2.chatSessionUser表中contactId(userId)对应的联系人昵称要修改
		String contactNameUpdate = null;
		if (!dbUserInfo.getNickName().equals(userInfo.getNickName())) {
			contactNameUpdate = userInfo.getNickName();//需要更新会话信息中的昵称
		}
		if (contactNameUpdate == null) {
			return;//不需要更新会话信息中的昵称
		}
		//更新redis中的token信息(昵称)
		TokenUserInfoDTO tokenUserInfoDTO = redisComponent.getTokenUserInfoDTOByUserId(userInfo.getUserId());
		tokenUserInfoDTO.setNickName(contactNameUpdate);
		redisComponent.saveTokenUserInfoDTO(tokenUserInfoDTO);
		//更新相关表冗余信息 更新联系人(userId)的昵称
		ChatSessionUser updateInfo = new ChatSessionUser();
		updateInfo.setContactName(contactNameUpdate);
		ChatSessionUserQuery chatSessionUserQuery = new ChatSessionUserQuery();
		chatSessionUserQuery.setContactId(userInfo.getUserId());
		chatSessionUserMapper.updateByParam(updateInfo, chatSessionUserQuery);//更新对应contactId(userId)的contactName

		//修改群昵称，发送ws消息(不入库), 注意消息要发给所有的好友
		MessageSendDTO messageSendDTO = new MessageSendDTO();
		messageSendDTO.setContactType(UserTypeEnum.USER.getType());

		UserContactQuery userContactQuery = new UserContactQuery();//查询所有的好友
		userContactQuery.setContactId(userInfo.getUserId());
		userContactQuery.setContactType(UserTypeEnum.USER.getType());
		userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
		List<UserContact> userContactList = userContactMapper.selectList(userContactQuery);

		messageSendDTO.setExtendData(contactNameUpdate);
		messageSendDTO.setMessageType(MessageTypeEnum.CONTACT_NAME_UPDATE.getType());
		messageSendDTO.setSendUserId(userInfo.getUserId());//发送人id
		messageSendDTO.setSendUserNickName(contactNameUpdate);//发送人昵称
		for (UserContact userContact : userContactList) {
			//消息循环发给所有好友
			messageSendDTO.setContactId(userContact.getUserId());
			messageHandler.sendMessage(messageSendDTO);
		}
	}

	/**
	 * 更新用户状态
	 * @param status 状态：启用 禁用
	 * @param userId 用户id
	 * @return
	 */
	@Override
	public void updateUserStatus(Integer status, String userId) {
		UserStatusEnum userStatusEnum = UserStatusEnum.getByStatus(status);
		if (userStatusEnum == null) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		UserInfo userInfo = new UserInfo();
		userInfo.setStatus(status);
		userInfoMapper.updateByUserId(userInfo, userId);
	}

	/**
	 * 强制下线
	 * @param userId 被强制下线的用户
	 * @return
	 */
	@Override
	public void forceOffLine(String userId) {
		//TODO 强制下线
		MessageSendDTO messageSendDTO = new MessageSendDTO();
		messageSendDTO.setContactType(UserTypeEnum.USER.getType());
		messageSendDTO.setMessageType(MessageTypeEnum.FORCE_OFF_LINE.getType());
		messageSendDTO.setContactId(userId);
		messageHandler.sendMessage(messageSendDTO);
	}

	private TokenUserInfoDTO getTokenUserInfoDTO(UserInfo userInfo) {
		TokenUserInfoDTO tokenUserInfoDTO = new TokenUserInfoDTO();
		//为DTO属性赋值
		tokenUserInfoDTO.setUserId(userInfo.getUserId());
		tokenUserInfoDTO.setNickName(userInfo.getNickName());
		//判断是否为超级管理员
		//超级管理员email，若有多个，则以“,”分开
		String[] adminEmails = appConfig.getAdminEmails().split(",");
		//看查出的用户的email是否在超级管理员email数组种
		if (ArrayUtils.contains(adminEmails, userInfo.getEmail())) {
			//是超级管理员
			tokenUserInfoDTO.setAdmin(true);
		} else {
			tokenUserInfoDTO.setAdmin(false);
		}
		return tokenUserInfoDTO;
	}
}